package cs236369.hw5.xml;

import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.log4j.Logger;

import cs236369.hw5.xml.jaxb.CrowdSourcing;

/**
 * {@link http://www.mkyong.com/java/jaxb-hello-world-example/}
 * 
 * @author Dror Baum
 * @author Amir Hasson
 * 
 */
public class XmlUtils
{
	public XmlUtils()
	{

	}
	
	/**
	 * writes the xml to the output stream.
	 * @param cs is the {@link CrowdSourcing} representing the xml
	 * @param os is the {@link OutputStream} to write to
	 * @return true on succes, false on fail
	 */
	public boolean writeToOutputStream(CrowdSourcing cs, OutputStream os)
	{

		Logger logger = Logger.getLogger(getClass());
		logger.info("converting CrowdSourcing to xml InputStream");
		try
		{
			logger.debug("generating JAXBcontext");
			JAXBContext jaxbContext = JAXBContext.newInstance(CrowdSourcing.class);
			logger.debug("generating Marshaller");
			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

			logger.debug("setting output to be preety...");
			jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			logger.debug("writing output to OutputStream");
			jaxbMarshaller.marshal(cs, os);
			logger.info("[OK] xml was writen to os");
			return true;
		}
		catch (JAXBException e)
		{
			logger.error("[FAIL] can't generate xml", e);
		}
		return false;
	}

	/**
	 * 
	 * @param xml is the xml {@link InputStream} which represents {@link CrowdSourcing} class.
	 * @return the jaxb object which represents this input stream, <br>
	 *         null on fail / wrong input
	 */
	public CrowdSourcing getFromInputStream(InputStream xml)
	{
		Logger logger = Logger.getLogger(getClass());

		if (null == xml)
		{
			logger.warn("[FAIL] can't load null InputStream");
			return null;
		}
		logger.info("converting xml InputStream to CrowdSourcing");
		try
		{
			logger.debug("generating JAXBcontext");
			JAXBContext jaxbContext = JAXBContext.newInstance(CrowdSourcing.class);
			logger.debug("generating unmarshaller");
			Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
			logger.debug("converting to cs");
			CrowdSourcing cs = (CrowdSourcing) jaxbUnmarshaller.unmarshal(xml);
			logger.info("[OK] returning cs");
			return cs;
		}
		catch (JAXBException e)
		{
			logger.error("[FAIL] can't load from input stream");
			return null;
		}
	}
	/**
	 * 
	 * @param xml is the xml {@link InputStream}
	 * @param xsl is the xsl {@link InputStream}
	 * @param os is the {@link OutputStream} to write the transformation to.
	 * @return true on success, false on fail
	 */
	public boolean convertInputStreamUsingXsl(InputStream xml, InputStream xsl, OutputStream os)
	{
		Logger logger = Logger.getLogger(getClass());

		if (null == xml || null == xsl)
		{
			logger.warn("[FAIL] can't load null InputStream");
			return false;
		}
		logger.info("converting xml InputStream to CrowdSourcing using XSLT");
		try
		{
			logger.debug("generating StreamSource for xsl");
			StreamSource xsltSource = new StreamSource(xsl);
			logger.debug("generating StreamSource for xml");
			StreamSource xmlSource = new StreamSource(xml);
			logger.debug("generating StreamResult for os");
			Result result = new StreamResult(os);
			
			logger.debug("generating TransformerFactory");
			TransformerFactory tf = TransformerFactory.newInstance();
			
			logger.debug("generating Transformer");
			Transformer transformer = tf.newTransformer(xsltSource);
			
			logger.debug("transforming xml using xslt");
			transformer.transform(xmlSource, result);
			
			logger.info("[OK] finish transforming");
			return true;
		}
		catch (TransformerConfigurationException e)
		{
			logger.error("[FAIL] can't generate transformer", e);
		}
		catch (TransformerException e)
		{
			logger.error("[FAIL] can't transform", e);
		}
		return false;
	}

}
